/**
 * Fonctions annexes nécessaire au fonctionnement des librairies indépendantes
 * Compatible Prototype.js 1.7.1+
 */
var ToolsPrototypeJS = new (function() {
	var $this = this;
	
	/**
	 * Récupère un ensemble d'élément dans un élément précis
	 */
	this.findElements = function(parent, css) {
		var s = new Selector(css);
		return s.findElements($this.$first(parent));
	}
	
	/**
	 * Récupère le premier élément dans un élément précis
	 */
	this.findElement = function(parent, css) {
		var elems = $this.findElements(parent, css);
		var elem = null;
		if (elems.length)  {
			elem = elems[0];
		}
		return elem;
	}
		
	
	/**
	 * Récupère un élément ou un ensemble d'élément, selon son id, une règle CSS, ou un objet
	 */
	this.$ = function(elementOrCSSOrID) {
		var result;
		if (typeof(elementOrCSSOrID) == "string") {
			var isCSSRule = (elementOrCSSOrID.indexOf(" ") >= 0 || elementOrCSSOrID.indexOf(".") >= 0 || elementOrCSSOrID.indexOf("#") >= 0);
			
			if (isCSSRule) {
				result = $$(elementOrCSSOrID);
			}
			else {
				result = $(elementOrCSSOrID);
				if (!result) {
					result = $$(elementOrCSSOrID);
				}
			}
		}
		else if (typeof(elementOrCSSOrID) == "object") {
			result = $(elementOrCSSOrID);
		}
		return result;
	}
	
	/**
	 * Récupère un élément ou le premier d'un ensemble d'élément, selon son id, une règle CSS, ou un objet
	 */
	this.$first = function(elementOrCSSOrID) {
		var element = $this.$(elementOrCSSOrID);
		if (Object.isArray(element)) {
			if (element.length > 0) {
				element = element[0];
			}
			else {
				element = null;
			}
		}
		return element;
	}
	
	/**
	 * Ajoute une classe CSS à un ou plusieurs éléments
	 */	
	this.hasClassName = function(element, c) {
		var element = $this.$(element);
		var hasClass = true;
		if (Object.isArray(element)) {
			for (var i = 0; i < element.length; i++) {
				hasClass = (hasClass && $this.hasClassName(element[i],c));
			}
		}
		else if (element) {
			hasClass = element.hasClassName(c);
		}
		return hasClass;
	}	
	/**
	 * Ajoute une classe CSS à un ou plusieurs éléments
	 */	
	this.addClassName = function(element, c) {
		var element = $this.$(element);
		
		if (Object.isArray(element)) {
			for (var i = 0; i < element.length; i++) {
				$this.addClassName(element[i],c);
			}
		}
		else if (element) {
			element.addClassName(c);
		}
	}
	
	/**
	 * Supprime une classe CSS à un ou plusieurs éléments
	 */
	this.removeClassName = function(element, c) {
		var element = $this.$(element);
		
		if (Object.isArray(element)) {
			for (var i = 0; i < element.length; i++) {
				$this.removeCSSClass(element[i],c);
			}
		}
		else if (element) {
			element.removeClassName(c);
		}
	}
	
	function getOption(options, name, def) {
		var value = def;
		if (typeof(options[name]) != "undefined") {
			value = options[name];
		}
		return value;
	}
	
	/**
	 * Crée une requête AJAX
	 *
	 * Paramètres à prendre en compte:
	 * - data: les paramètres, au format Object
	 * - url: l'url de la requête AJAX
	 * - type: la méthode (POST / GET)
	 * - headers: les headers de la requête en plus
	 * - error: fonction en cas d'erreur (autre que 2XX)
	 * - success: fonction en cas de succès (2XX)
	 * - mimeType: le mime type a écrasé
	 * Pour error et success, le 1er paramètre renvoyé doit être le texte reçu, le 2ème l'objet XMLHttpRequest (ou wrapper)
	 */
	this.ajax = function(options) {
		var type = getOption(options, "type", "POST");
		var url = getOption(options, "url", "");
		var mimeType = getOption(options, "mimeType", "");
		var data = getOption(options, "data", {});
		var headers = getOption(options, "headers", {});
		var onerror = getOption(options, "error", function(){});
		var onsuccess = getOption(options, "success", function(){});
		var ajax = new Ajax.Request(url, {
			requestHeaders: headers,
			onSuccess: function(response) {
				return onsuccess(response.responseText, response);
			},
			onFailure: function (response) {
				return onerror(null, response);
			},
			onCreate: function(o, xhr) {
				if (mimeType) {
					o.request.transport.overrideMimeType(mimeType);
				}
				if (FormData && data instanceof FormData) {
					o.request.options.postBody = data;
					o.request.setRequestHeaders = function() { };
					$this.lastRequest = o;
					//o.request.transport.send(data);
					//return false;
				}
			},
			method: type.toLowerCase(),
			parameters: data
		});
		
	}
	
	/**
	 * Ajoute un évènement au chargement de la page
	 */
	this.onready = function(f) {
		document.observe("dom:loaded",f);
	}
	
	/**
	 * Obtient le total d'offset cumulé correspondant à son x et y (left et top)
	 * Renvoie un objet contenant les attributs left (int) et top (int)
	 */
	this.getCumulativeOffset = function(element) {
		var element = $this.$first(element);
		return element.cumulativeOffset();
	};
	
	/**
	 * Ajout une fonction sur un évènement d'un élément HTML précis
	 */
	this.on = function(event, element, f, bubbles) {
		var element = $this.$(element);
		
		if (Object.isArray(element)) {
			for (var i = 0; i < element.length; i++) {
				$this.on(event, element[i], f, bubbles);
			}
		} else if (element) {
			element.observe(event,f, bubbles);
		}
	};
	
	/**
	 * Transforme un élément <form> en un objet name: val
	 */
	this.serialize = function(form, retObject) {
		var f = $this.$first(form);
		var o = f.serialize(retObject);
		return o;
	}
	
	this.css = function(element, name, value) {
		if (element.length > 0) {
			for (var i = 0; i < element.length; i++) {
				$this.css(element[i], name, value);
			}
		}
		else if (element) {
			var o = {};
			o[name] = value;
			element.setStyle(o);
		}
	}
});
